<template>
  <div>
    <el-form ref="deptForm" :model="form" :rules="rules" label-width="120px">
      <el-form-item label="部门名称" prop="name">
        <el-input
          v-model="form.name"
          style="width: 80%"
          placeholder="1-50个字符"
        />
      </el-form-item>
      <el-form-item label="部门编码" prop="code">
        <el-input
          v-model="form.code"
          style="width: 80%"
          placeholder="1-50个字符"
        />
      </el-form-item>
      <el-form-item label="部门负责人" prop="manager">
        <el-select
          v-model="form.manager"
          style="width: 80%"
          placeholder="请选择"
        >
          <el-option v-for="obj in employeesList" :key="obj.id" :value="obj.username" />
        </el-select>
      </el-form-item>
      <el-form-item label="部门介绍" prop="introduce">
        <el-input
          v-model="form.introduce"
          style="width: 80%"
          placeholder="1-300个字符"
          type="textarea"
          :rows="3"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="hSubmit">确定</el-button>
        <el-button @click="hCancel">取消</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
// 复习: el-form表单验证
// 1. el-form上, ref(为了js兜底验证), :model="绑定的数据对象", :rules="规则对象"
// 2. el-form-item上, prop="对象key名"
// 3. el-表单标签 v-model="数据对象.key名"
export default {
  name: 'DepartDialog',
  props: {
    // 员工列表
    employeesList: {
      type: Array,
      default: () => []
    },
    // 可接也可以不接(原因: 子拿到隐藏的变量无用)
    // 添加/编辑状态
    isEdit: {
      type: Boolean,
      default: false
    },
    // 用于验证code和name的部门列表数组
    originList: {
      type: Array,
      default: () => []
    },
    // 正在编辑的此对象的部门ID
    clickDepartId: {
      type: String,
      default: ''
    }
  },
  data() {
    // 验证部门编码(不能和所有人重复)
    const validCode = (rule, value, callback) => {
      // 添加子部门的时候:  部门编码, 和所有部门都不能重复
      // rule规则对象, value绑定值, callback回传给检验的结果
      // 用includes方法: 让数组直接是code值, 判断value是否再这个数组里, 如果在返回true
      let codeList = this.originList.map(item => item.code) // ['XZB', 'code值', '..']
      if (this.isEdit) {
        // 编辑部门: 部门编码可以用自己本身的, 修改的时候, 是不能和其他部门的编码重复
        // 问题: 外面代码会把编辑时部门编码和自己比较, 直接冲突报错了, 但是逻辑不通~我是可以用自己本身编码的
        // 解决: 把大数组里正在编辑的这个部门对象过滤掉, 把其他部门对象留下来形成一个新数组
        // 代码: filter判断, 数组里每个对象, 哪个的id不等于点击编码部门id就留下来
        // this.originList.filter(item => item.id !== this.clickDepartId) 值是: [{}, {}, {}] 没有了正在编辑的部门对象
        // filter返回符合=>里的条件的对象, 形成新数组在原地(不改变原数组)

        // 扩展: 为啥用code判断!==不行, 因为value值一变, 就把对应的对象过滤掉了永远判断不到.
        codeList = this.originList.filter(item => item.id !== this.clickDepartId).map(item => item.code)
      }
      codeList.includes(value) ? callback(new Error(`编码${value}已经存在了`)) : callback()
    }
    // 验证部门名字(不能和同级部门重复)
    const validName = (rule, value, callback) => {
      // 添加子部门: 部门名字不能和同级部门重名
      // 点击部门后, 怎么找到下属的同级部门?
      // 公式: 子部门pid = 父部门id (点击添加子部门的时候, 点击这行部门就是父级部门, clickDepartId就是父id)
      let nameList = this.originList.filter(item => item.pid === this.clickDepartId).map(item => item.name)

      if (this.isEdit) {
        // 编辑部门: 部门名字不能和同级部门重名
        // 点击编辑部门后, 怎么找到同级部门?
        // 已知: 所有部门的数组(对象id和pid), 点击这一行部门id
        // (1): 通过编辑部门id, 上大数组里去找到这个部门对象
        const theObj = this.originList.find(item => item.id === this.clickDepartId)
        // (2): 拿出pid值
        const targetPid = theObj.pid
        // (3): 找到所有同级部门的对象(同级部门的pid都是相等的)
        // const result = this.originList.filter(item => item.pid === targetPid)
        // (4): 找到所有同级部门的对象, 还得把自己过滤掉
        nameList = this.originList.filter(item => item.pid === targetPid && item.id !== this.clickDepartId).map(item => item.name)
      }

      nameList.includes(value) ? callback(new Error(`部门名字${value}已经存在`)) : callback()
    }

    return {
      // 表单数据对象
      form: {
        name: '', // 部门名称
        code: '', // 部门编码
        manager: '', // 部门管理者
        introduce: '' // 部门介绍
      },
      // 表单校验规则
      rules: {
        name: [
          { required: true, message: '部门名称不能为空', trigger: 'blur' },
          { min: 1, max: 50, message: '部门名称要求1-50个字符', trigger: 'blur' },
          { validator: validName, trigger: 'blur' }
        ],
        code: [
          { required: true, message: '部门编码不能为空', trigger: 'blur' },
          { min: 1, max: 50, message: '部门编码要求1-50个字符', trigger: 'blur' },
          { validator: validCode, trigger: 'blur' }
        ],
        manager: [
          { required: true, message: '部门负责人不能为空', trigger: 'blur' }
        ],
        introduce: [
          { required: true, message: '部门介绍不能为空', trigger: 'blur' },
          { min: 1, max: 300, message: '部门介绍要求1-300个字符', trigger: 'blur' }
        ]
      }
    }
  },
  methods: {
    // 确认按钮-点击事件
    hSubmit() {
      this.$refs.deptForm.validate(valid => {
        if (!valid) return // valid为false, 有表单没通过校验, 进入if里阻止代码往下执行
        // 部门的创建
        // 把数据对象传回给父组件
        this.$emit('departEV', { ...this.form })
        // 清空表单内容(必须3步)
        // 1. el-form上有ref为了获取到el-form组件对象调用内置方法resetFields()
        // 2. el-form上有model="表单对象变量名", 把最初始的对象赋予进去, 为了重置做准备
        // 3. el-form-item上需要有prop字段, 值对应v-model的对象属性名(因为它会去form对象里用prop字段找到原来的默认值)
        // 工作原理: 调用resetFields()内源码, model选项保存的初始对象和初始对象值, 给form对象几个属性, 进行初始值覆盖
        // this.form.name = model初始form对象name值(空字符串)// 其他4个同理
        // 右侧this.form和左侧formObj变量指向的是同一个对象内存空间
        // 所在在置空的时候, 就把父formObj影响了, 就导致请求的时候, 发送给后台的都是空值了
        // 解决: 传给父的时候, 拷贝一个新对象, 让内部this.form和formObj脱离关系(浅拷贝)
        this.$refs.deptForm.resetFields()
        // 直接把form对象替换掉, v-model后面变量改变, vue响应式更新v-model对应绑定标签值(思路和上面不太一样)
        // this.form = {
        //   name: '', // 部门名称
        //   code: '', // 部门编码
        //   manager: '', // 部门管理者
        //   introduce: '' // 部门介绍
        // }
        // 关闭弹框
        // 如果要改变.sync指定的右侧变量值
        // 采用此语法:
        // this.$emit('update:props变量名', 值)
        this.$emit('update:dialogVisible', false)
        // 只是子传父(父那边方便), 不会直接修改props变量值
        // 流程-> 子传父(在父那边改变dialogVisible的值, 新的值会通过父->子流回到props变量里)

        // this.$emit('close', false)
      })
    },

    // 取消按钮-点击事件
    hCancel() {
      // 子想要直接绑定给父变量一个值
      this.$refs.deptForm.resetFields()
      this.$emit('update:dialogVisible', false)
    }
  }
}
</script>

<style lang="scss" scoped></style>
